package com.heima.article.service.impl;


import com.alibaba.fastjson.JSON;
import com.heima.apis.wemedia.IWemediaClient;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleHotService;
import com.heima.article.service.ApArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.mess.ArticleBehaviorAggsData;
import com.heima.model.wemedia.pojos.WmChannel;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ApArticleHotServiceImpl implements ApArticleHotService {

    @Autowired
    private ApArticleMapper apArticleMapper;

    @Override
    public void compuateHotArticle() {
new ThreadPoolTaskExecutor()
        //1. 查询最近N天的文章列表
        //1.1 定义开始时间
        String beginDate = DateTime.now().minusDays(550).toString("yyyy-MM-dd 00:00:00");

        //1.2 根据开始时间查询文章列表
        List<ApArticle> apArticleList = apArticleMapper.loadLastDaysArticleList(beginDate);

        //2. 计算所有文章分值，得到带分值的文章列表
        List<HotArticleVo> hotArticleVoList = computeAllArticleScore(apArticleList);

        //3. 为所有频道（普通频道和推荐频道）缓存Top30热点文章列表数据
        saveHotArticleToRedis(hotArticleVoList);

    }

    @Autowired
    private IWemediaClient wemediaClient;

    /**
     * 为所有频道（普通频道和推荐频道）缓存Top30热点文章列表数据
     * @param apArticleList
     */
    private void saveHotArticleToRedis(List<HotArticleVo> apArticleList) {
        //1 为普通频道缓存Top30热点文章列表数据
        //1.1 调用Feign接口查询全部频道列表
        List<WmChannel> wmChannelList = wemediaClient.listAllChannels();

        //1.2 遍历频道列表筛选出每个频道对应的文章列表并缓存
        for (WmChannel wmChannel : wmChannelList) {

            //筛选每个频道对应的文章列表
            List<HotArticleVo> channelArticleList = apArticleList.stream().filter(x -> x.getChannelId().equals(wmChannel.getId())).collect(Collectors.toList());

            //将文章列表按照分值排序、取前30条、存入Redis
            String redisKeyChannel = ArticleConstants.HOT_ARTICLE_FIRST_PAGE + wmChannel.getId();

            this.saveAndSortArticle(channelArticleList, redisKeyChannel);
        }

        //2 为推荐频道缓存Top30热点文章列表数据
        String redisKeyAll =  ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG;
        this.saveAndSortArticle(apArticleList, redisKeyAll);
    }

    @Autowired
    private CacheService cacheService;

    /**
     * 公共方法：将文章列表按照分值排序、取前30条、存入Redis
     * @param articleVoList
     * @param redisKey
     */
    private void saveAndSortArticle(List<HotArticleVo> articleVoList, String redisKey) {
        if(articleVoList!=null && articleVoList.size()>0){
            //1.对文章列表按照分值倒排序
            articleVoList = articleVoList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());

            //2.取前30条文章作为热点文章
            if(articleVoList.size()>30){
               // articleVoList = articleVoList.subList(0, 30);
                articleVoList = articleVoList.stream().limit(30).collect(Collectors.toList());
            }

            //3.将热点文章列表转为JSON存入Redis
            cacheService.set(redisKey, JSON.toJSONString(articleVoList));
        }
    }

    private List<HotArticleVo> computeAllArticleScore(List<ApArticle> apArticleList) {
        List<HotArticleVo> hotArticleVoList = new ArrayList<>();
        //遍历文章列表
        for (ApArticle apArticle : apArticleList) {
            //计算每个文章的分值
            int score = computeSingleArticleScore(apArticle);

            //将文章转为带分值属性的文章
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle,hotArticleVo);
            hotArticleVo.setScore(score);

            //将带分值的文章添加到新的文章列表
            hotArticleVoList.add(hotArticleVo);
        }

        return hotArticleVoList;
    }

    /**
     * 计算每一个文章的分值
     * @param apArticle
     * @return
     */
    private int computeSingleArticleScore(ApArticle apArticle) {
        int score = 0;
        //累加阅读行为的分值
        if(apArticle.getViews()!=null){
            score += apArticle.getViews();
        }
        //累加点赞行为分值
        if(apArticle.getLikes()!=null){
            score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }

        //累加评论行为分值
        if(apArticle.getComment()!=null){
            score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }

        //累加收藏行为分值
        if(apArticle.getCollection()!=null){
            score += apArticle.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }

        return score;
    }

    @Autowired
    private ApArticleService apArticleService;

    @Override
    public void recomputeHotArticle(ArticleBehaviorAggsData data) {
        //1.更新文章表行为数据
        //1.1 查询文章表数据
        ApArticle apArticle = apArticleService.getById(data.getArticleId());

        //1.2 累加行为数据
        ApArticle apArticleDB = new ApArticle();
        apArticleDB.setId(apArticle.getId()); //更新条件
        //累加阅读行为数量
        if(apArticle.getViews()!=null){
            apArticleDB.setViews(apArticle.getViews() + data.getView());
        }
        //累加点赞行为数量
        if(apArticle.getLikes()!=null){
            apArticleDB.setLikes(apArticle.getLikes() + data.getLike());
        }

        //累加评论行为数量
        if(apArticle.getComment()!=null){
            apArticleDB.setComment(apArticle.getComment() + data.getComment());
        }

        //累加收藏行为数量
        if(apArticle.getCollection()!=null){
            apArticleDB.setCollection(apArticle.getCollection() + data.getCollect());
        }

        //1.3 执行更新   update ap_article set views=?,likes=?,collection=?,comment=? where id=?
        apArticleService.updateById(apArticleDB);

        //2.计算文章分值
        //2.1 重新查询文章
        apArticle = apArticleService.getById(data.getArticleId());

        //2.2 计算文章分值结果乘3
        int score = this.computeSingleArticleScore(apArticle) * 3;

        //3.比较或更新当前频道的Redis热点文章数据
        compareOrUpdateRedis(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());

        //4.比较或更新推荐频道的Redis热点文章数据
        compareOrUpdateRedis(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
    }

    /**
     * 比较或更新Redis热点文章数据
     * @param apArticle  当前文章
     * @param score  当前文章最新的分值
     * @param redisKey
     */
    private void compareOrUpdateRedis(ApArticle apArticle, int score, String redisKey) {
        //1.查询Redis中热点文章列表
        String hotArticleVoListJSON = cacheService.get(redisKey);
        List<HotArticleVo> hotArticleVoList = JSON.parseArray(hotArticleVoListJSON, HotArticleVo.class);

        //2.如果热点文章列表为空，则直接将当前文章添加到热点文章列表
        if(hotArticleVoList.size()==0){
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle,hotArticleVo);
            hotArticleVo.setScore(score);
            hotArticleVoList.add(hotArticleVo);
        } else {
            //3.如果热点文章列表不为空
            //3.1 如果当前文章在热点文章列表中，则更新掉这个文章
            boolean isNotExists = true; //默认文章不在热点文章列表中
            for (HotArticleVo hotArticleVo : hotArticleVoList) {
                if(hotArticleVo.getId().equals(apArticle.getId())){
                    BeanUtils.copyProperties(apArticle,hotArticleVo);
                    hotArticleVo.setScore(score);
                    isNotExists = false;
                    break;
                }
            }

            if(isNotExists){
                //3.2 如果当前文章不在热点文章列表中且热点文章列表数量不够30条，则直接将当前文章添加到热点文章列表
                if(hotArticleVoList.size()<30){
                    HotArticleVo hotArticleVo = new HotArticleVo();
                    BeanUtils.copyProperties(apArticle,hotArticleVo);
                    hotArticleVo.setScore(score);
                    hotArticleVoList.add(hotArticleVo);
                } else {
                    //3.3 如果当前文章不在热点文章列表中且热点文章列表数量已够30条，则比较当前文章与最后一条热点文章的分值，大于替换

                    //获取最后一条热点文章
                    HotArticleVo hotArticleVoLast = hotArticleVoList.get(hotArticleVoList.size() - 1);

                    //比较当前文章与最后一条热点文章的分值，大于就替换
                    if(score>hotArticleVoLast.getScore()){
                        //将最后一条热点文章从热点文章列表中删除
                        hotArticleVoList.remove(hotArticleVoLast);

                        //将当前文章添加到热点文章列表中
                        HotArticleVo hotArticleVo = new HotArticleVo();
                        BeanUtils.copyProperties(apArticle,hotArticleVo);
                        hotArticleVo.setScore(score);
                        hotArticleVoList.add(hotArticleVo);
                    }
                }

            }

        }

        //4.对热点文章列表按照分值重新排序
        hotArticleVoList = hotArticleVoList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());

        //5.更新Redis中的热点文章列表数据
        cacheService.set(redisKey, JSON.toJSONString(hotArticleVoList));
    }
}
